import time
from selenium import webdriver
from selenium.common.exceptions import TimeoutException
from selenium.webdriver.chrome.webdriver import WebDriver
from selenium.webdriver.support.wait import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
from selenium.webdriver.common.by import By
from selenium.webdriver.common.action_chains import ActionChains
from lib.log import logger
from selenium.webdriver.common.keys import Keys


class Browser(object):
    def __init__(self, ie=False, option=None) -> None:
        super().__init__()
        if ie:
            self.driver = webdriver.Ie()
        else:
            if option is None:
                option = webdriver.ChromeOptions()
                option.add_experimental_option('excludeSwitches', ['enable-automation'])
            self.driver = webdriver.Chrome(options=option)
        self.driver.maximize_window()

    def load(self, url, sleep_time=5):
        self.driver.get(url)
        time.sleep(sleep_time)

    def refresh(self):
        self.driver.refresh()

    def title(self):
        return self.driver.title

    def wait_window_closed(self, handle, wait_time=10):
        s = time.time()
        while True:
            already_in = handle in self.driver.window_handles
            if already_in:
                time.sleep(0.5)
            else:
                break
            if (time.time() - s) > wait_time:
                raise Exception("Window not Closed")

    def current_window_handle(self):
        return self.driver.current_window_handle

    def switch_to_window(self, handle=None):
        if handle:
            self.driver.switch_to.window(handle)
            return
        handle = self.driver.current_window_handle
        allhandle = self.driver.window_handles
        for h in allhandle:
            if handle != h:
                self.driver.switch_to.window(h)

    def switch_to_window_by_title(self, title, wait_time=10):
        c = self.driver.current_window_handle
        s = time.time()
        while True:
            time.sleep(0.5)
            allhandle = self.driver.window_handles
            for h in allhandle:
                self.driver.switch_to.window(h)
                if self.driver.title == title:
                    return
                if (time.time() - s) > wait_time:
                    self.driver.switch_to.window(c)
                    raise Exception(f"Switch to window[{title}] timeout")

    def return_to_window(self):
        allhandle = self.driver.window_handles
        for h in allhandle:
            self.driver.switch_to.window(h)

    def close(self):
        self.driver.close()

    def switch_to_frame(self, xpath=None, index=None, wait_time=10, sleep_time=1):
        if xpath:
            frame = self.find_element(xpath=xpath, wait_time=wait_time)
            self.driver.switch_to.frame(frame)
            print(f"swicth to frame: {xpath}")
        if index is not None:
            self.driver.switch_to.frame(index)
            print(f"swicth to frame: {index}")
        time.sleep(sleep_time)

    def default_content(self):
        self.driver.switch_to.default_content()

    def find_element(self, xpath=None, css_selector=None, wait_time=10):
        if xpath:
            f = lambda el: self.driver.find_element_by_xpath(xpath)
        if css_selector:
            f = lambda el: self.driver.find_element_by_css_selector(css_selector)
        return WebDriverWait(self.driver, wait_time).until(f)

    def find_elements(self, xpath=None, css_selector=None, wait_time=10):
        if xpath:
            f = lambda el: self.driver.find_elements_by_xpath(xpath)
            if wait_time == 0:
                return f(xpath)
        if css_selector:
            f = lambda el: self.driver.find_elements_by_css_selector(css_selector)
            if wait_time == 0:
                return f(css_selector)
        return WebDriverWait(self.driver, wait_time).until(f)

    def select(self, xpath=None, css_selector=None, text=None, wait_time=10, sleep_time=1):
        els = self.find_elements(xpath=xpath, css_selector=css_selector, wait_time=wait_time)
        for i, el in enumerate(els):
            if el.text == text:
                el.click()
                logger.info(f'下拉框{css_selector}选择:{text}')
                time.sleep(sleep_time)
                return
        logger.info(f'下拉框{css_selector}未找到选项:{text}')

    def click(self, xpath, text='', wait_time=10, sleep_time=1):
        self.find_element(xpath=xpath, wait_time=wait_time).click()
        logger.info(f'点击按钮:{xpath}|{text}')
        time.sleep(sleep_time)

    def text(self, xpath, wait_time=10):
        return WebDriverWait(self.driver, wait_time).until(lambda el: self.driver.find_element_by_xpath(xpath)).text

    def click_by_css(self, css_selector, text='', wait_time=10, sleep_time=1):
        btn = WebDriverWait(self.driver, wait_time).until(
            lambda el: self.driver.find_elements_by_css_selector(css_selector))
        btn.click()
        logger.info(f'点击按钮:{css_selector}|{text}')
        time.sleep(sleep_time)

    def fill_input(self, xpath, value, input_name="", wait_time=10, sleep_time=1):
        input = WebDriverWait(self.driver, wait_time).until(lambda el: self.driver.find_element_by_xpath(xpath))
        input.send_keys(value)
        logger.info(f'{input_name}输入值:{value}')
        time.sleep(sleep_time)

    def execute_script(self, script, *args):
        return self.driver.execute_script(script, args)

    def move_to(self, el):
        ActionChains(self.driver).move_to_element(el).perform()

    def get_cookies(self):
        return self.driver.get_cookies()

    def quit(self):
        self.driver.quit()

    def await_show_click(self, xpath, wait_time=10):
        WebDriverWait(self.driver, wait_time).until(EC.element_to_be_clickable(
            (By.XPATH, xpath))).click()

    def is_not_visible(self, xpath, wait_time=10):
        # 一直等待某个元素消失，默认超时10秒
        WebDriverWait(self.driver, wait_time).until_not(EC.visibility_of_element_located((By.XPATH, xpath)))

    def is_visible(self, xpath, wait_time=10):
        # 一直等待某个元素出现，默认超时10秒
        WebDriverWait(self.driver, wait_time).until(EC.visibility_of_element_located((By.XPATH, xpath)))

    def clear_input(self, xpath, data):
        # 清空input输入框
        send_keys_input = self.find_element(xpath=xpath)
        send_keys_input.send_keys(Keys.CONTROL + 'a')  # 输入框数据全选
        send_keys_input.send_keys(Keys.DELETE)  # 删除input输入框里的数据
        send_keys_input.send_keys(data)  # 输入数据

    def switch_to_alert(self, wait_time=10):
        return WebDriverWait(self.driver, wait_time).until(EC.alert_is_present())

def create_chrome():
    return Browser()


def create_IE():
    return Browser(ie=True)
